// poj2007
// 题意：给定n个点，求凸包，并从(0, 0)开始按逆时针顺序输出凸包。
//
// 题解：其实就是凸包。
//
// run: $exec < input
// opt: 0
// flag: -g
// std: c++98
#include <iostream>
#include <algorithm>
#include <vector>

template <class T>
struct point
{
	typedef T value_type;
	point(value_type x, value_type y) : x(x), y(y) {};
	point() {};
	value_type x, y;
};

int const maxn = 100;

typedef int cord_type;
std::vector<point<cord_type> > points(maxn);
std::vector<point<cord_type> > stack(maxn);

template <class T>
int signum(T const & x)
{
	return (x < 0 ? -1 : x > 0 ? + 1 : 0);
}

template <class T>
T ccw(point<T> const & a, point<T> const & b, point<T> const & c)
{
	return signum((long long)(b.x - a.x) * (c.y - a.y) - (long long)(b.y - a.y) * (c.x - a.x));
}

template <class T>
struct cmp
{
	bool operator()(point<T> const & a, point<T> const & b)
	{
		return a.y < b.y || (a.y == b.y && a.x < b.x);
	}
};

int main()
{
	int n = 0;
	for (; std::cin >> points[n].x >> points[n].y; n++);
	std::sort(points.begin(), points.begin() + n, cmp<cord_type>());

	int top = 0;
	for (int i = 0; i < n; i++) {
		while (top >= 2 && ccw(stack[top - 2], stack[top - 1], points[i]) < 0)
			top--;
		stack[top++] = points[i];
	}
	int t = top + 1;
	for (int i = n - 2; i >= 0; i--) {
		while (top >= t && ccw(stack[top - 2], stack[top - 1], points[i]) < 0)
			top--;
		stack[top++] = points[i];
	}

	// the perimeter of the convex hull
	int orign = 0, m = top - 1;
	for (int i = 0; i < m; i++)
		if (!stack[i].x && !stack[i].y) { orign = i; break; }
	for (int i = 0; i < m; i++)
		std::cout << "(" << stack[(orign + i) % m].x << "," << stack[(orign + i) % m].y << ")\n";
}

